#include "ParticleManager.h"
#include "MLProgressbar.h"

ParticleManager::ParticleManager(
	int frame_size_x, int frame_size_y,
	double frame_rate,
	std::vector<VelocityStream>& streams,
	std::map<std::string, Color>& colors,
	double brightness,
	Byte alpha,
	Double2 lifespan_range,
	Location radius_range,
	Double2 v_range,
	Double2 a_delta_range,
	Double2 init_angle_range,
	Double2 a_angle_range,
	double blur_sigma,
	double particle_sparseness,
	int record_radius,
	double trailing_decay
) :MLObj(frame_size_x, frame_size_y, frame_rate) {
	printf((char*)u8"正在初始化粒子轨道……\n");
	size_t tracks_num = streams.size();
	GLuint glsl = Utils::activateShader("./GLSL/ParticleVertex.glsl", "./GLSL/ParticleFragment.glsl");
	_mix_glsl = Utils::activateShader("./GLSL/MixVertex.glsl", "./GLSL/MixFragment.glsl");
	GLuint blur_glsl = Utils::activateShader("./GLSL/GaussianBlurVertex.glsl", "./GLSL/GaussianBlurFragment.glsl");
	MLProgressbar progressbar(tracks_num, (char*)u8"初始化进度");
	init_angle_range.x *= M_PI / 180;
	init_angle_range.y *= M_PI / 180;
	a_angle_range.x *= M_PI / 180;
	a_angle_range.y *= M_PI / 180;
	for (size_t i = 0; i < tracks_num; i++) {
		ParticleTrack track(
			frame_size_x, frame_size_y,
			frame_rate,
			streams[i],
			colors[streams[i].name],
			alpha,
			brightness,
			lifespan_range,
			radius_range,
			v_range,
			a_delta_range,
			init_angle_range,
			a_angle_range,
			glsl,
			_mix_glsl,
			particle_sparseness * streams.size(),
			record_radius
		);
		_tracks.push_back(track);
		progressbar.update();
	}
	_blur_kernel = Drawer::createGaussianBlurKernel(blur_sigma, blur_glsl, frame_size_x, frame_size_y);
	_trailing_frame = MLFrame(frame_size_x, frame_size_y);
	Utils::clearFrame(_trailing_frame.fbo);
	_trailing_decay = trailing_decay / frame_rate;
	_mix_with_alpha_glsl = Utils::activateShader("./GLSL/MixVertex.glsl", "./GLSL/MixWithAlphaFragment.glsl");
}

void ParticleManager::get_frame(size_t frame_index, MLFrame& frame) {
	MLFrame new_frame(_frame_size_x, _frame_size_y);
	for (size_t i = 0; i < _tracks.size(); i++) {
		_tracks[i].get_frame(frame_index, new_frame);
	}
	new_frame.mix_alpha(_trailing_frame, 1, 1 - _trailing_decay, _mix_with_alpha_glsl);
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		throw "";
	}
	Drawer::applyGaussianBlur(_blur_kernel, _trailing_frame.fbo, _trailing_frame.rbo, _trailing_frame.texture);
	frame.mix(new_frame, _mix_glsl);
	_trailing_frame.clear();
	_trailing_frame = new_frame;
}
